package io.gitee.sections.sequence.autoconfigure;

import io.gitee.sections.sequence.core.SequenceDefinition;
import io.gitee.sections.sequence.core.SequenceGenerator;
import io.gitee.sections.sequence.core.cache.CacheProvider;
import io.gitee.sections.sequence.core.cache.InMemoryCacheProvider;
import io.gitee.sections.sequence.core.cache.RedisCacheProvider;
import io.gitee.sections.sequence.core.dao.DataAccessor;
import io.gitee.sections.sequence.core.dao.DataSourceDataAccessor;
import io.gitee.sections.sequence.core.dao.DataSourceProperties;
import io.gitee.sections.sequence.core.dao.StandaloneDataAccessor;
import io.gitee.sections.sequence.core.impl.SequenceManager;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.*;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;

@Configuration
@AutoConfigureAfter({DataSourceAutoConfiguration.class, RedisAutoConfiguration.class})
public class SequenceAutoConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "sequence.config.datasource")
    public DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @ConfigurationProperties(prefix = "sequence.config.sequences")
    public List<SequenceDefinition> sequenceInfos() {
        return new ArrayList<>();
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnBean(DataSource.class)
    @ConditionalOnProperty(prefix = "sequence.config.datasource", name = {"url"}, matchIfMissing = true)
    public DataAccessor dataSourceDataAccessor(DataSource dataSource) {
        return new DataSourceDataAccessor(dataSource);
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "sequence.config.datasource", name = {"url"})
    public DataAccessor standaloneDataAccessor(DataSourceProperties dataSourceProperties) {
        return new StandaloneDataAccessor(dataSourceProperties);
    }

    @Configuration
    @ConditionalOnClass(RedisTemplate.class)
    public static class redisCachePoolConfig {
        @Bean
        @ConditionalOnBean(RedisTemplate.class)
        public CacheProvider redisCachePool(RedisTemplate<Object, Object> redisTemplate) {
            return new RedisCacheProvider(redisTemplate);
        }
    }

    @Bean
    public CacheProvider inMemoryCachePool() {
        return new InMemoryCacheProvider();
    }

    @Bean
    @ConditionalOnMissingBean
    SequenceGenerator sequenceGenerator(DataAccessor dataAccessor, List<CacheProvider> cacheProviders, List<SequenceDefinition> sequenceDefinitions) {
        SequenceManager sequenceManager = new SequenceManager(dataAccessor, cacheProviders);
        sequenceManager.load(sequenceDefinitions);
        return sequenceManager;
    }
}
